package com.ztesoft.zsmart.zcm.monitor.utils;

import com.ztesoft.zsmart.core.exception.BaseAppException;
import com.ztesoft.zsmart.core.log.ZSmartLogger;
import com.ztesoft.zsmart.core.utils.DateUtil;
import com.ztesoft.zsmart.core.utils.StringUtil;
import com.ztesoft.zsmart.zcm.core.exception.ExceptionPublisher;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;

/**
 * <Description>
 *
 * @author zhang.yi
 * @version 1.0
 * @taskId
 * @CreateDate 2019-03-08 10:48:27
 * @since V1.0
 * @see com.ztesoft.zsmart.zcm.monitor.utils
 */
@Component("fileUploadHelper")
@Scope("prototype")
public class FileUploadHelper {
    private static final ZSmartLogger LOGGER = ZSmartLogger.getLogger(FileUploadHelper.class);

    private static final String FILE_SEPRATOR = File.separator;

    public static final String DEFAULT_PATH = "/app/upload";

    private static final String FILE_SUFFIX = ".";

    private static final String FILE_TEMP_LEFT = "(";

    private static final String FILE_TEMP_RIGHT = ")";

    private static final long MILI_SECONDS = 1000;

    /**
     * <Description> 文件名生成方式
     * 
     * @author zhang.yi
     * @version 1.0
     * @taskId
     * @CreateDate 2019-03-08 01:08:30
     * @since V1.0
     * @see com.ztesoft.zsmart.zcm.monitor.utils
     */
    public enum FileNameMode {
        /**
         * 以覆盖的方式生成上传文件名
         */
        REPLACE(1),
        /**
         * 以括号加数字递增的方式生成上传文件名
         */
        BACKUP(2),
        /**
         * 以当前毫秒数生成上传文件名
         */
        RANDOM(3);
        private Integer value;

        FileNameMode(Integer value) {
            this.value = value;
        }

        public Integer getValue() {
            return this.value;
        }

        /**
         * 通过值获取枚举的类型
         * 
         * @param value 具体值
         * @return FileNameMode
         */
        public static FileNameMode getModeByValue(Integer value) {
            for (FileNameMode v : values()) {
                if (v.value.equals(value)) {
                    return v;
                }
            }
            return null;
        }
    }

    /**
     * Description: 通过指定文件命名方式将文件上传到某一路径下 @method uploadFile @param request : HttpServletRequest上传文件流 @param uploadPath
     * : 上传路径 @param fileNameMode : 上传文件方式 @author zhang.yi @taskId @return java.lang.String 上传后的文件路径 @throws
     */
    public String uploadFile(HttpServletRequest request, String uploadPath, FileNameMode fileNameMode)
        throws BaseAppException {
        String path = null;
        long startTime = System.currentTimeMillis();
        LOGGER.info("Start upload file, current time is: {}", DateUtil.getStandardNowTime());
        try {
            // 将当前上下文初始化给 CommonsMutipartResolver （多部分解析器）
            CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
            MultipartHttpServletRequest multiRequest = null;
            // 检查form中是否有enctype="multipart/form-data" 并将request变成多部分request
            if (multipartResolver.isMultipart(request)) {
                multiRequest = (MultipartHttpServletRequest) request;
            }
            else {
                multiRequest = multipartResolver.resolveMultipart(request);
            }

            // 获取multiRequest 中所有的文件名
            Iterator<String> iter = multiRequest.getFileNames();

            while (iter.hasNext()) {
                // 一次遍历所有文件
                MultipartFile file = multiRequest.getFile(iter.next());
                String fileName = file.getOriginalFilename();
                if (!fileName.endsWith(".json") && !fileName.endsWith(".JSON")) {
                    ExceptionPublisher.publish(fileName + "非法审核规则文件格式导入", "ZCM-NMS-00001");
                }

                path = this.createFile(file, uploadPath, fileNameMode);
            }
        }
        catch (IOException e) {
            LOGGER.error(e);
        }

        long endTime = System.currentTimeMillis();
        LOGGER.info("End upload file, current time is: {}", DateUtil.getStandardNowTime());
        LOGGER.info("Upload file finish, total coast is {} seconds", (endTime - startTime) / MILI_SECONDS);
        return path;
    }

    private String createFile(MultipartFile file, String uploadPath, FileNameMode fileNameMode) throws IOException {
        String newFilePath = null;
        if (null != file) {
            if (StringUtil.isEmpty(uploadPath)) {
                uploadPath = DEFAULT_PATH + FILE_SEPRATOR;
            }

            if (!uploadPath.endsWith(FILE_SEPRATOR)) {
                uploadPath = uploadPath + FILE_SEPRATOR;
            }

            if (createDirectory(uploadPath)) {
                LOGGER.info("Upload file name: {}" + file.getOriginalFilename());
                File newFile = getNewFile(uploadPath, file.getOriginalFilename(), fileNameMode);
                // 上传
                file.transferTo(newFile);
                newFilePath = newFile.getCanonicalPath();
            }

        }
        return newFilePath;
    }

    /**
     * Description: 通过文件命名方式，生成新的文件名 @method getNewFile @param path : 文件存放路径，不含文件名，以/结尾 @param originalFileName :
     * 旧文件名 @param fileNameMode : 文件命名方式 @author zhang.yi @taskId @return java.io.File 新文件完整路径 @throws
     */
    public static File getNewFile(String path, String originalFileName, FileNameMode fileNameMode) {
        File newFile = null;
        switch (fileNameMode) {
            case REPLACE:
                newFile = new File(path + originalFileName);
                break;
            case BACKUP:
                File file = new File(path + originalFileName);
                boolean isExists = file.exists();
                if (!isExists) {
                    // 如果文件不存在，不需要重命名
                    newFile = file;
                    // return newFile;
                    break;
                }
                // 如果存在了，则继续命名
                newFile = getBackUpFile(path, originalFileName, 0);
                break;
            case RANDOM:
                String suffix = originalFileName.substring(originalFileName.lastIndexOf(FILE_SUFFIX));
                long now = System.currentTimeMillis();
                newFile = new File(path + now + suffix);
                break;
            default:
                break;
        }
        return newFile;
    }

    /**
     * Description: 生成备份文件，以(+ 数字+ )的方式递增生成文件名 @method getBackUpFile @param filePath : 文件存放路径，不含文件名，以/结尾 @param
     * originalFileName :旧文件名 @param index : 递增索引，从0开始 @author zhang.yi @taskId @return java.io.File 新文件完整路径 @throws
     */
    public static File getBackUpFile(String filePath, String originalFileName, int index) {
        boolean isExists = true;
        File newFile = null;
        String prefix = originalFileName.substring(0, originalFileName.lastIndexOf(FILE_SUFFIX));
        String suffix = originalFileName.substring(originalFileName.lastIndexOf(FILE_SUFFIX));
        StringBuffer buffer = new StringBuffer();
        while (isExists) {
            index++;
            buffer.append(filePath);
            buffer.append(prefix);
            buffer.append(FILE_TEMP_LEFT);
            buffer.append(index);
            buffer.append(FILE_TEMP_RIGHT);
            buffer.append(suffix);

            newFile = new File(buffer.toString());
            isExists = newFile.exists();
            if (!isExists) {
                return newFile;
            }
            return getBackUpFile(filePath, originalFileName, index);
        }
        return newFile;
    }

    /**
     * Description: 创建目录 @method createDirectory @param path : 目录路径 @author zhang.yi @taskId @return boolean
     * true创建成功，false创建失败 @throws
     */
    public static boolean createDirectory(String path) {
        File uploadPathFile = new File(path);
        boolean isExists = uploadPathFile.exists();
        boolean isDirectory = uploadPathFile.isDirectory();
        if (!isExists || !isDirectory) {
            boolean flag = uploadPathFile.mkdirs();
            if (!flag) {
                LOGGER.error("Create folder {} failed", path);
                return false;
            }
        }
        return true;
    }

    /*
     * public static void main(String[] args) { String uploadPath = "D:/upload/files"; if
     * (StringUtil.isEmpty(uploadPath)) { uploadPath = DEFAULT_PATH + FILE_SEPRATOR; } if
     * (!uploadPath.endsWith(FILE_SEPRATOR)) { uploadPath = uploadPath + FILE_SEPRATOR; } if
     * (createDirectory(uploadPath)) { File newFile = getNewFile(uploadPath, "kapacitorTasks.json",
     * FileNameMode.BACKUP); try { newFile.createNewFile(); java.io.FileWriter writer = new java.io.FileWriter(newFile);
     * java.io.PrintWriter printWriter = new java.io.PrintWriter(writer); int random = (int) (Math.random() * 10 + 1);
     * printWriter.write(random + ""); printWriter.flush(); printWriter.close(); writer.close(); } catch (IOException e)
     * { e.printStackTrace(); } } }
     */
}
